package se392.ateam2006.resourcemgmt;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.ejb.CreateException;
import javax.ejb.EJB;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.util.Calendar;

import se392.ateam2006.authentication.GroupEntity;
import se392.ateam2006.exceptions.EquipmentFoundException;
import se392.ateam2006.exceptions.MethodNotImplementedException;
import se392.ateam2006.meetingmgmt.MeetingMgmtLocal;
import se392.ateam2006.meetingmgmt.meeting.MeetingEntity;
import se392.ateam2006.resourcemgmt.equipment.EquipmentEntity;
import se392.ateam2006.resourcemgmt.equipment.EquipmentEntityPK;
import se392.ateam2006.resourcemgmt.participant.ParticipationEntity;
import se392.ateam2006.resourcemgmt.participant.exclusionset.ExclusionRangeEntity;
import se392.ateam2006.resourcemgmt.room.RoomEntity;
import se392.ateam2006.user.UserEntity;
import se392.ateam2006.user.UserMgmtLocal;
import se392.ateam2006.utils.EmailSender;
import se392.ateam2006.utils.OveridableCalendar;

/**
 * Stateless EJB to handle all operations relating to resources (rooms, exclusion ranges, equipment, participations)
 * @author Ateam (Matthew Bennett, Claire Melton, Shingai Manyiwa, John Adderley)
 * @version 25/03/07
 */
@Stateless
public class ResourceMgmtBean implements Serializable, ResourceMgmtRemote, ResourceMgmtLocal {

    private final long TEN_MINUTES_IN_MILLIS = 600000;
    @PersistenceContext
    private EntityManager em;
    @EJB
    private UserMgmtLocal users;
    @EJB
    private MeetingMgmtLocal meetings;

    /** 
     * Default constructor required as this is an EJB
     */
    public ResourceMgmtBean() {
    }

    /**
     * Create and persist a room
     * @param roomID - String, the ID of the room
     * @param capacity - int, the capacity of the room (how many people)
     * @param location - String, location of the room
     * @param owner - String, the owner of the room
     * @return RoomEntity - the newly persisted room
     */
    public RoomEntity createRoom(String roomID, int capacity, String location, String owner) {

        RoomEntity room = null;
        room = (RoomEntity) em.find(RoomEntity.class, roomID);
        if (room == null) {
            room = new RoomEntity(roomID, capacity, location, owner);
            em.persist(room);
        }
        em.flush();
        return room;
    }
    
    public void createRoom(RoomEntity room) {
        RoomEntity roomTemp = (RoomEntity) em.find(RoomEntity.class, room.getRoomID());
        if (roomTemp == null) {
            em.persist(room);
        }
    }

    /**
     * Create and persist an exclusion range
     * @param ue - UserEntity, the user to create the exclusion range for
     * @param me - MeetingEntity, the meeting to create the exclusion range for
     * @param start - Calendar, the start date/time of the exclusion range
     * @param end - Calendar, the end date/time of the exclusion range
     * @param pref - boolean, is this a preference range rather than an exclusion range?
     * @throws CreateException
     */
    public ExclusionRangeEntity createExclusionRangeEntity(UserEntity ue, MeetingEntity me,
            Calendar start, Calendar end, boolean pref) throws CreateException {

        if (null == ue) {
            throw new CreateException("User was null");
        } else if (null == me) {
            throw new CreateException("Meeting was null");
        } else if (null == start) {
            throw new CreateException("Start Date was invalid");
        } else if (null == end) {
            throw new CreateException("End Date was invalid");
        } else if (start.compareTo(end) > 0) {
            throw new CreateException("End Date was before Start Date");
        } else if ((end.getTimeInMillis() - start.getTimeInMillis()) < TEN_MINUTES_IN_MILLIS) {
            throw new CreateException("Duration of preference/exclusion set was less than 10 minutes");
        } else {

            Collection<ExclusionRangeEntity> excSets;
            excSets = getExclusionSetsForParticipantAndMeetings(ue, me);

            if (excSets != null) {
                excSets = (Collection<ExclusionRangeEntity>) excSets;
                for (ExclusionRangeEntity o : excSets) {
                    if (o.getStartDate() != null && o.getEndDate() != null) {
                        if (checkDateRangesForOverlaps(start, end, o.getStartDate(), o.getEndDate())) {
                            throw new CreateException("Exclusion set overlap encountered.");
                        }
                    }
                }
            }

            int cut = me.getCutOffPeriod();
            GregorianCalendar cutOffDate = new OveridableCalendar();

            //cutOffDate.setTimeInMillis(me.getEndDateRange().getTimeInMillis() - (cut * 24 * 60 *60 * 1000));
            cutOffDate.setTimeInMillis(me.getEndDateRange().getTimeInMillis());
            cutOffDate.add(Calendar.DAY_OF_YEAR, -1 * cut);
            //TODO: Make this use OveridableCalendar
            Calendar today = OveridableCalendar.getInstance();
            today.set(Calendar.SECOND, 0);

            if (today.getTimeInMillis() >= cutOffDate.getTimeInMillis()) {
                throw new CreateException("Cut Off period has passed");
            }

            if (start.getTimeInMillis() < me.getStartDateRange().getTimeInMillis()) {
                throw new CreateException("The start date is before the start date range of the meeting.");
            } else if (end.getTimeInMillis() > me.getEndDateRange().getTimeInMillis()) {
                throw new CreateException("The end date is after the end date range of the meeting.");
            } else if (!hasParticipation(ue, me)) {
                throw new CreateException("The user is not a participant in the meeting.");
            }

            ExclusionRangeEntity ere = new ExclusionRangeEntity(ue, me, start, end, pref);
            em.persist(ere);
            return ere;
        }
    }

    public ExclusionRangeEntity createExclusionRangeEntity(UserEntity ue, MeetingEntity me,
            boolean pref) throws CreateException {
        if (null == ue) {
            throw new CreateException("User was null");
        } else if (null == me) {
            throw new CreateException("Meeting was null");
        } else {

            Collection<ExclusionRangeEntity> excSets;
            excSets = getExclusionSetsForParticipantAndMeetings(ue, me);

            int cut = me.getCutOffPeriod();
            GregorianCalendar cutOffDate = new OveridableCalendar();

            //cutOffDate.setTimeInMillis(me.getEndDateRange().getTimeInMillis() - (cut * 24 * 60 *60 * 1000));
            cutOffDate.setTimeInMillis(me.getEndDateRange().getTimeInMillis());
            cutOffDate.add(Calendar.DAY_OF_YEAR, -1 * cut);
            //TODO: Make this use OveridableCalendar
            Calendar today = OveridableCalendar.getInstance();
            today.set(Calendar.SECOND, 0);



            if (today.getTimeInMillis() >= cutOffDate.getTimeInMillis()) {
                throw new CreateException("Cut Off period has passed");
            }

            if (!hasParticipation(ue, me)) {
                throw new CreateException("The user is not a participant in the meeting.");
            }

            ExclusionRangeEntity ere = new ExclusionRangeEntity(ue, me, null, null, pref);
            em.persist(ere);
            return ere;
        }

    }

    /**
     * Create and persist an exclusion range
     * @param ue - UserEntity, the user to create the exclusion range for
     * @param start - Calendar, the start date/time of the exclusion range
     * @param end - Calendar, the end date/time of the exclusion range
     * @param pref - boolean, is this a preference range rather than an exclusion range?
     */
    public ExclusionRangeEntity createExclusionRangeEntity(UserEntity user, Calendar start, Calendar end, boolean pref) {

        ExclusionRangeEntity ere = new ExclusionRangeEntity(user, start, end, pref);
        em.persist(ere);
        return ere;
    }

    /**
     * Check two date ranges for overlaps (used when validating exclusion ranges)
     * @param startA - the start of the first range
     * @param endA - the end of the first range
     * @param startB - the start of the second range
     * @param endB - the end of the second range
     * @return boolean - do the ranges overlap?
     */
    private boolean checkDateRangesForOverlaps(Calendar startA, Calendar endA, Calendar startB, Calendar endB) {
        //Just make sure we don't get false overlaps
        // We deal with 10-min intervals - a second isn't gonna matter
        endA.add(Calendar.SECOND, -1);
        endB.add(Calendar.SECOND, -1);

        
        if ((startA.compareTo(startB) < 0) && (endA.compareTo(startB) < 0)) {
            //First range starts and finishes before second starts - no overlap
            endA.add(Calendar.SECOND, 1);
            endB.add(Calendar.SECOND, 1);
            return false;
        }

        if ((startB.compareTo(startA) < 0) && (endB.compareTo(startA) < 0)) {
            //Second range starts and finishes before first starts - no overlap
            endA.add(Calendar.SECOND, 1);
            endB.add(Calendar.SECOND, 1);
            return false;
        }

        endA.add(Calendar.SECOND, 1);
        endB.add(Calendar.SECOND, 1);
        return true;
    }

    /**
     * Get the number of pieces of equipment in the database
     * @return int - the number of pieces of equipment
     */
    public int getEquipmentCount() {
        throw new MethodNotImplementedException("ResourceMgmtBean.getEquipmentCount()");
    }

    public Collection<EquipmentEntity> getAllEquipments() {
        em.flush();
        Query q = em.createQuery("SELECT r FROM EquipmentEntity r");
        return q.getResultList();
    }

    /**
     * Get the number of exclusion (and preference) sets in the database
     * @return int - the number of exclusion/preference sets
     */
    public int getExclusionSetsCount() {
        Collection<ExclusionRangeEntity> exSets = getAllExclusionsAndPreferences();
        return exSets.size();
    }

    /**
     * Get all of the exclusion/preference sets that exist for the specified user
     * @param user - UserEntity, the user entity to look for
     * @return Collection - all the exclusion/preference sets for the specified user
     */
    public Collection getExclusionSetsForParticipant(UserEntity user) {
        Query q = em.createQuery("SELECT p FROM ExclusionRangeEntity p WHERE p.userEnt.email = '" + user.getEmail() + "'");
        return (Collection) q.getResultList();
    }

    /**
     * Get all of the exclusion/preference sets for a given user and meeting
     * @param user - UserEntity, the user to look for
     * @param meeting - MeetingEntity, the meeting to look for
     * @return Collection - all of the exclusion/preference sets that share the same user and meeting
     */
    public Collection getExclusionSetsForParticipantAndMeetings(UserEntity user, MeetingEntity meeting) {
        Query q = em.createQuery("SELECT p FROM ExclusionRangeEntity p WHERE p.userEnt.email = '" + user.getEmail() + "' AND p.meetingEnt.id = '" + meeting.getId() + "'");
        return (Collection) q.getResultList();
    }

    /**
     * Get all of the exclusion/preference sets for a given user and meeting
     * @param user - UserEntity, the user to look for
     * @param meeting - MeetingEntity, the meeting to look for
     * @return Collection - all of the exclusion/preference sets that share the same user and meeting
     */
    public Collection getExclusionSetsForMeetingId(String meetingId) {
        Query q = em.createQuery("SELECT p FROM ExclusionRangeEntity p WHERE p.meetingEnt.id = '" + meetingId + "'");
        return (Collection) q.getResultList();
    }

    /**
     * Get all of the locations that exist in the database
     * @return Collection - all of the locations
     */
    public Collection getLocations() {
        throw new MethodNotImplementedException("ResourceMgmtBean.getLocations()");
    }

    /**
     * Get all of the preference sets for a specified user
     * @param userId - String, the ID of the user to look for
     * @return Collection - all of the preference sets for the user
     */
    public Collection getPreferenceSetsForParticipant(String userId) {
        Query q = em.createQuery("SELECT p FROM ExclusionRangeEntity p WHERE p.userEnt.email = '" + userId + "' and p.preferenceSet = 'true'");
        return (Collection) q.getResultList();
    }

    /**
     * Create a participation between a user and a meeting
     * @param me - MeetingEntity, the meeting to create a participation for
     * @param ue - UserEntity, the user to create a participation for
     * @return ParticipationEntity - the newly created participation between 'me' and 'ue'
     * @throws CreateException
     */
    public ParticipationEntity createParticipation(MeetingEntity me, UserEntity ue) throws CreateException {
        return this.createParticipation(me, ue, false);
    }

    /**
     * Create a participation between a user and a meeting
     * @param me - MeetingEntity, the meeting to create a participation for
     * @param ue - UserEntity, the user to create a participation for
     * @param isActive - boolean, is the user an active participant of the meeting?
     * @return ParticipationEntity - the newly created participation between 'me' and 'ue'
     * @throws CreateException
     */
    public ParticipationEntity createParticipation(MeetingEntity me, UserEntity ue, boolean isActive) throws CreateException {
        if (hasParticipation(ue, me)) {
            throw new CreateException("Participation already exists!");
        }

        if (me.getRoom() != null) {
            int roomSize = me.getRoom().getCapacity();
            int proposedMeetingSize = me.getRequestedRoomSize();
            int meetingSize = getMeetingParticipantCount(me);
            if (meetingSize == roomSize) {
                throw new CreateException("Too many participants for assigned room - " +
                        "please choose a bigger room before assigning more participants");
            }
            if (meetingSize == proposedMeetingSize) {
            // The following line should be uncommented - but feature creep is bad
            //me.setRequestedRoomSize(proposedMeetingSize +1);
            }
        }

        ParticipationEntity pe = new ParticipationEntity(ue, me, isActive);
        em.merge(ue);
        em.merge(me);
        em.persist(pe);


        ParticipationEntity[] pes = new ParticipationEntity[1];
        pes[0] = pe;
        EmailSender sender = new EmailSender(pes, "");
        sender.createInviteMessage();

        return pe;
    }

    /**
     * Determin whether a participation exists between the given user and meeting
     * @param ue - UserEntity, the user to look for
     * @param me - MeetingEntity, the meeting to look for
     * @return boolean - does a participation exist between 'ue' and 'me'?
     */
    public boolean hasParticipation(UserEntity ue, MeetingEntity me) {
        if (getParticipant(ue, me) == null) {
            return false;
        } else {
            return true;
        }
    }

    /**
     * Remove a participation entity
     * @param pe - ParticipationEntity, the participation to remove
     * @throws IllegalArgumentException
     */
    public void removeParticipation(ParticipationEntity pe) throws IllegalArgumentException {
        Query q = null;
        ParticipationEntity participant = null;
        try {
            participant = em.find(ParticipationEntity.class, pe.getId());
            em.remove(participant);
            q = em.createQuery("Delete from ParticipationEntity p " +
                    "where p.id = '" + pe.getId() + "'");
            q.executeUpdate();
        } catch (Exception iae) {
            if (iae instanceof IllegalArgumentException) {
                throw (IllegalArgumentException) iae;
            } else {
                iae.printStackTrace();
            }
        }
    }

    /**
     * Find a participation based on a user and a meeting
     * @param ue - UserEntity, the user to look for
     * @param me - MeetingEntity, the meeting to look for
     * @return ParticipationEntity - the participation between 'ue' and 'me' if it
     *      exists, otherwise null
     */
    public ParticipationEntity getParticipant(UserEntity ue, MeetingEntity me) {

        Query q = em.createQuery("Select p from ParticipationEntity p where" +
                " p.userEntity.email = '" + ue.getEmail() +
                "' and p.meeting.id = '" + me.getId() + "'");
        ParticipationEntity result = null;

        try {
            result = (ParticipationEntity) q.getSingleResult();
        } catch (NoResultException e) {
            System.err.println("No resulting ParticipationEntities with user '" + ue.getEmail() + "' and meeting '" + me.getId() + "'");
        }

        return result;
    }

    /*
     * Returns all the equipment associated with a specified room
     * 
     * @param theRoom - the specified room
     * @return Collection - all the equipment in the room
     */
    public Collection getEquipmentByRoomId(RoomEntity theRoom) {
        Query q = em.createQuery("SELECT e FROM EquipmentEntity e where" +
                " e.roomID = '" + theRoom.getRoomID() + "'");
        ArrayList<EquipmentEntity> c = new ArrayList(q.getResultList());
        return c;

    }

    /**
     * Get the number of rooms in the database
     * @return int - the number of rooms in the database
     */
    public int getRoomCount() {
        Query q = em.createQuery("SELECT r FROM RoomEntity r");
        return q.getResultList().size();
    }

    /**
     * Get a list of all rooms that are in a specified location
     * @param location - String, the location to look for
     * @return Collection - all of the rooms at the specified location
     */
    public Collection getRoomsByLocation(String location) {
        throw new MethodNotImplementedException("ResourceMgmtBean.getRoomsByLocation()");
    }

    /**
     * Find a room based on its ID
     * @param roomID - String, the ID of the room to find
     * @return RoomEntity - the found room (or null)
     */
    public RoomEntity findRoomByID(String roomID) {
        return em.find(RoomEntity.class, roomID);
    }

    /**
     * Find a piece of equipment based on its serial ID
     * @param serialID - String, the serial ID of the equipment to find
     * @return EquipmentEntity - the found equipment (or null)
     */
    public EquipmentEntity findEquipmentBySerialID(String serialID, String roomID) {
        EquipmentEntityPK pk = new EquipmentEntityPK(serialID, roomID);
        return em.find(EquipmentEntity.class, pk);
    }

    public EquipmentEntity findEquipmentBySerialID(String serialID) {
        Query q = em.createQuery("SELECT e FROM EquipmentEntity e where" +
                " e.id = '" + serialID + "'");
        Collection results = q.getResultList();
        ArrayList<EquipmentEntity> list = new ArrayList<EquipmentEntity>();
        list.addAll(results);
        return list.get(0);
    }

    /**
     * Submit a participant's response for a meeting invitation
     * @param part - ParticipationEntity, the participation containing the user and meeting we're dealing with
     * @param coll - Collection of ExclusionRangeEntity, the user's exclusion/preference ranges for this meeting
     */
    public void participantResponse(ParticipationEntity part, Collection<ExclusionRangeEntity> coll) {
        throw new MethodNotImplementedException("ResourceMgmtBean.getRoomsByLocation()");
    }

    /**
     * Remove all of the default start times
     */
    public void removeAllDefaultStartTimes() {
        throw new MethodNotImplementedException("ResourceMgmtBean.getRoomsByLocation()");
    }

    /**
     * Remove all of the equipment from the database
     */
    public void removeAllEquipment() {
        Query q = em.createQuery("DELETE FROM EquipmentEntity");
        q.executeUpdate();
    }

    /**
     * Method to remove exclusion sets based on which meeting they belong to
     * Note: This method probably could be done better and might not want to be here
     * ccf4
     * @param meetingID
     * @return
     */
    public void removeExclusionSetsByMeetingId(String meetingID) {
        em.flush();
        Collection<ExclusionRangeEntity> exSets = getAllExclusionsAndPreferences();
        for (ExclusionRangeEntity set : exSets) {
            if (set.getMeeting().getId().equals(meetingID)) {
                em.remove(set);
            }
        }
        Query q = em.createQuery("DELETE FROM ExclusionRangeEntity e WHERE e.meetingEnt.id = '" + meetingID + "'");
        System.out.println(q.executeUpdate() + " entries deleted from ExclusionRangeEntity table");
    }

    /**
     * Remove all of the exclusion/preference sets from the database
     */
    public void removeAllExclusionSets() {
        em.flush();
        Collection<ExclusionRangeEntity> exSets = getAllExclusionsAndPreferences();
        for (ExclusionRangeEntity set : exSets) {
            em.remove(set);
        }

        Query q = em.createQuery("DELETE FROM ExclusionRangeEntity");
        System.out.println(q.executeUpdate() + " entries deleted from ExclusionRangeEntity table");
    }

    /**
     * Delete a room
     * @param room - RoomEntity, the room to delete
     */
    public void deleteRoom(RoomEntity room) {
        em.merge(room);
        em.flush();
        RoomEntity rm = em.find(RoomEntity.class, room.getRoomID());
        Collection<MeetingEntity> meets = meetings.getAllMeetings();
        for (MeetingEntity me : meets) {
            System.err.println("Found a meeting using room");
            if (me.getRoom() != null && me.getRoom().getRoomID().equals(rm.getRoomID())) {
                me.setRoom(null);
                em.merge(me);
            }
        }

        em.remove(rm);
        Query q = em.createQuery("DELETE FROM RoomEntity r where r.roomID = '" + rm.getRoomID() + "'");
        q.executeUpdate();
    }

    /**
     * Remove all of the rooms from the database
     */
    public void removeAllRooms() {
        em.flush();
        Collection<RoomEntity> rooms = getAllRooms();
        for (RoomEntity rm : rooms) {
            deleteRoom(rm);
        }
    }

    /**
     * Remove a preference/exclusion set from the database
     * @param set - ExclusionRangeEntity, the range to remove
     */
    public void removePreAndExSet(ExclusionRangeEntity set) {
        Query q = em.createQuery("DELETE FROM ExclusionRangeEntity r where r.id='" +
                set.getId() + "'");
        q.executeUpdate();
    }

    /**
     * Set the owner of a piece of equipment
     * @param serialID - String, the ID of the piece of equipment
     * @param owner - String, the new owner of the piece of equipment
     */
    public void setEquipmentOwner(String serialID, String owner, String roomID) {
        EquipmentEntity equipment = findEquipmentBySerialID(serialID, roomID);
        if (null != equipment) {
            equipment.setOwner(owner);
            em.merge(equipment);
        }
        em.flush();
    }

    /**
     * Set the equipment that a room contains.
     * 
     * @param serialNo - String equipment serial number.
     * @param type - String type of equipment.
     * @param location - String location of where the equipment lives.
     * @param status - Boolean status for whether the equipment is fixed to that location.
     */
    public void setRoomEquipment(String serialNo, String type, String location, boolean status) throws EquipmentFoundException {
        EquipmentEntity equipment = findEquipmentBySerialID(serialNo, location);
        if (null == equipment) {
            RoomEntity room = new RoomEntity();
            room = findRoomByID(location);
            equipment = new EquipmentEntity(serialNo, type, room, status, null);
            em.persist(equipment);
        } else {
            throw new EquipmentFoundException("The Piece of equipment is already in the database");
        }
        em.flush();
    }

    /**
     * Set the equipment needed for a participation (user and meeting)
     * This seems a strange method... not sure why it's needed. We've inherited this method
     *      signature from last year's group...
     * @param userId - String, the ID of the user of the participation
     * @param meetingId - String, the ID of the meeting of the participation
     * @param equipment - String[], a list of all needed equipment
     */
    public void setParticipantEquipment(String userId, String meetingId, String[] equipment) {
        throw new MethodNotImplementedException("ResourceMgmtBean.setEquipmentOwner()");
    }

    /**
     * Set the owner of a room
     * @param roomId - String, the ID of the room we're going to change
     * @param owner - String, the new owner of the room
     */
    public void setRoomOwner(String roomId, String owner) {
        this.findRoomByID(roomId).setOwner(owner);
    }

    /**
     * Get all of the exclusion/preference sets in the database
     * @return Collection - all of the exclusion/preference sets
     */
    public Collection getAllExclusionsAndPreferences() {
        em.flush();
        Query q = em.createQuery("SELECT e FROM ExclusionRangeEntity e");
        return q.getResultList();
    }

    /**
     * Get all of the rooms in the database
     * @return Collection - all of the rooms
     */
    public Collection getAllRooms() {
        em.flush();
        Query q = em.createQuery("SELECT r FROM RoomEntity r");
        return q.getResultList();
    }
    
    public Collection<RoomEntity> getAllRoomsAllowed(UserEntity user) {
        Collection<RoomEntity> allRooms = this.getAllRooms();
        Collection<RoomEntity> allowedRooms = new ArrayList<RoomEntity>();
        for(RoomEntity room: allRooms) {
            String owner = room.getOwner();
            for(GroupEntity group: user.getPermissions()) {
                if(group.getGroupid().equalsIgnoreCase(owner)) {
                    allowedRooms.add(room);
                }
            }
        }
        return allowedRooms;
    } 

    /**
     * Slightly (?) hacky method used when testing
     * This allows us to disable sending emails each time we run the tests so we don't get spammed
     * @param areWeJustTesting - boolean, are we testing?
     */
    public void setTestingMode(boolean areWeJustTesting) {
        EmailSender.isTesting = areWeJustTesting;
    }

    /**
     * Set the date used when running the FitNesse tests
     * As the dates in the fit tables occur in the past, we need to fake the
     *      system time to allow them to pass. This isn't cheating - it's just that
     *      the dates in the fit tables haven't been updated and all occur in 2004, whereas
     *      we live in the real world in 2007
     * @param d - Date, the date to set to
     */
    public void setTestDate(Date d) {
        GregorianCalendar gCal = new GregorianCalendar();
        gCal.setTime(d);
        OveridableCalendar.overriddenDate = gCal;
    }

    /**
     * Get the number of participants for a given meeting
     * @param me - MeetingEntity, the meeting entity to look for
     * @return int - the number of participants
     */
    public int getMeetingParticipantCount(MeetingEntity me) {
        Query q = em.createQuery("Select p from ParticipationEntity p where" +
                " p.meeting.id = '" + me.getId() + "'");
        return q.getResultList().size();
    }

    /**
     * Get the number of active participants for a given meeting
     * @param me - MeetingEntity, the meeting entity to look for
     * @return int - the number of active participants
     */
    public int getActiveParticipantCount(MeetingEntity me) {
        Query q = em.createQuery("Select p from ParticipationEntity p where" +
                " p.meeting.id = '" + me.getId() +
                "' and p.active = 'true'");
        return q.getResultList().size();
    }

    /**
     * Get all of the participants for a given meeting
     * @param me - MeetingEntity, the meeting entity to look for
     * @return Collection - all the participants of the meeting
     */
    public Collection getMeetingParticipants(MeetingEntity me) {
        Query q = em.createQuery("Select p from ParticipationEntity p where" +
                " p.meeting.id = '" + me.getId() + "'");
        return q.getResultList();
    }

    /**
     * Remove all of the participations in the database
     */
    public void removeAllParticipations() {
        Collection<ParticipationEntity> parts = getAllParticipations();
        for (ParticipationEntity p : parts) {
            removeParticipation(p);
        }
    }

    /**
     * Get all of the participations
     * @return Collection - all of the participations
     */
    public Collection getAllParticipations() {
        Query q = em.createQuery("Select p from ParticipationEntity p");
        return q.getResultList();

    }

    /**
     * Find all of the participations for a specified user
     * i.e. all of the meetings that a user is going to attend
     * @param u - UserEntity, the user to look for
     * @return Collection - all of the participations for the specified user
     */
    public Collection findParticipationsByUser(UserEntity u) {
        Query q = em.createQuery("Select p from ParticipationEntity p where" +
                " p.userEntity.email = '" + u.getEmail() + "'");
        return q.getResultList();
    }

    /**
     * Delete an exclusion/preference range
     * @param p - ExclusionRangeEntity, the exclusion range to delete
     */
    public void deleteExclusionRange(ExclusionRangeEntity p) {
        Query q = null;
        ExclusionRangeEntity exclusion = null;
        try {
            exclusion = em.find(ExclusionRangeEntity.class, p.getId());
            em.remove(exclusion);
            q = em.createQuery("Delete from ExclusionRangeEntity p " +
                    "where p.id = '" + p.getId() + "'");
            q.executeUpdate();
        } catch (Exception iae) {
            if (iae instanceof IllegalArgumentException) {
                throw (IllegalArgumentException) iae;
            } else {
                System.out.println("Error removing exclusion range");
                iae.printStackTrace();
            }
        }
    }

    /**
     * Find all of the exclusion ranges for a specified user
     * @param u - UserEntity, the user to look for
     * @return Collection - all of the exclusion ranges for the user
     */
    public Collection findExclusionRangesByUser(UserEntity u) {
        Query q = em.createQuery("Select p from ExclusionRangeEntity p where" +
                " p.userEnt.email = '" + u.getEmail() + "'");
        return q.getResultList();
    }
}
